package cn.kys.modules.system.service.impl;

import cn.kys.modules.system.pojo.GeometryPojo;
import cn.kys.modules.system.pojo.SubtaskGeom;
import cn.kys.modules.system.repository.ImportShp2PgRepository;
import cn.kys.modules.system.service.GetDeptIdByLoginUser;
import cn.kys.modules.system.service.ImportShp2PgService;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.postgis.PostgisNGDataStoreFactory;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.JTS;
import org.geotools.jdbc.JDBCDataStore;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.locationtech.jts.geom.Geometry;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.Name;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

@Slf4j
@Primary
@Service
public class ImportShp2PgServiceImpl implements ImportShp2PgService {

    @Autowired
    private ImportShp2PgRepository importShp2PgRepository;

    private int ScanSuffixCount = 0;
    private ArrayList<String> ScanSuffixFiles = new ArrayList<String>();

    @Value("${file.shpFile}")
    private String shpFile;

    @Value("${spring.datasource.druid.url}")
    private String databaseUrl;

    @Value("${spring.datasource.druid.username}")
    private String username;

    @Value("${spring.datasource.druid.password}")
    private String password;


    @Autowired
    private GetDeptIdByLoginUser getDeptIdByLoginUser;
    @Value("${adminUserIncludeStr}")
    private String adminUserIncludeStr;

    // 加部门权限的id
    public Long getDeptId() {
        return getDeptIdByLoginUser.getDeptId();
    }

    // 加部门权限的用户名
    public String getUserName() {
        return getDeptIdByLoginUser.getUserName();
    }


    /**
     * @return
     * @Author zhaoxw
     * @Description //TODO 判断shp数据是否存在在pg数据库中
     * @Date 14:38 2023/12/29
     **/
    @Override
    public boolean shpHasImported(MultipartFile[] shpFiles) {
        boolean isExist = false;
        String shpPath = multipartFileShp2File(shpFiles);
        File file = new File(shpPath);
        String fileName = file.getName();
        String noExtensionName = fileName.substring(0, fileName.lastIndexOf("."));

        List<Map> tableList = importShp2PgRepository.pgTableList();
        for (Map map : tableList) {
            String tableName = map.get("tablename").toString();
            if (noExtensionName.toLowerCase().equalsIgnoreCase(tableName.trim())) {
                isExist = true;
                break;
            }
        }
        return isExist;
    }


    /**
     * @return
     * @Author zhaoxw
     * @Description //TODO 获取数据库连接对象
     * @Date 15:46 2023/12/29
     **/
    @Override
    public JDBCDataStore getDataStore() {

        System.setProperty("org.geotools.referencing.forceXY", "true");

        String[] parts = databaseUrl.split(":|/|//");
        String ip = parts[4];
        String port = parts[5];
        String database = parts[6];

        Map<String, Object> params = new HashMap<>();
        // 必须是字符串 postgis
        params.put(PostgisNGDataStoreFactory.DBTYPE.key, "postgis");
        // ip
        params.put(PostgisNGDataStoreFactory.HOST.key, ip);
        // 端口
        params.put(PostgisNGDataStoreFactory.PORT.key, port);
        // 数据库模式
        params.put(PostgisNGDataStoreFactory.SCHEMA.key, "public");
        // 数据库名称
        params.put(PostgisNGDataStoreFactory.DATABASE.key, database);
        params.put(PostgisNGDataStoreFactory.USER.key, username);
        params.put(PostgisNGDataStoreFactory.PASSWD.key, password);

        JDBCDataStore dataStore = null;
        try {
            DataStore ds = DataStoreFinder.getDataStore(params);
            if (ds == null) {
                System.out.println("连接postgres失败");
            } else {
                dataStore = (JDBCDataStore) ds;
                System.out.println("连接postgres成功");
            }

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("连接postres出错");
        }
        return dataStore;
    }


    /**
     * @return
     * @Author zhaoxw
     * @Description //读取shapefile文件
     * @Date 15:47 2023/12/29
     * @Date 10:45 2024/2/21
     **/
    @Override
    public SimpleFeatureSource readShp(File file) {
        System.setProperty("org.geotools.referencing.forceXY", "true");

        SimpleFeatureSource featureSource = null;

        ShapefileDataStore shpDataStore = null;
        try {
            shpDataStore = new ShapefileDataStore(file.toURI().toURL());
            //设置编码
            Charset charset = Charset.forName("UTF8");
            shpDataStore.setCharset(charset);
            String tableName = shpDataStore.getTypeNames()[0];
            featureSource = shpDataStore.getFeatureSource(tableName);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            shpDataStore.dispose();
        }
        return featureSource;

    }

    /**
     * @return
     * @Author zhaoxw
     * @Description //TODO 创建表
     * @Date 15:47 2023/12/29
     **/
    @Override
    public JDBCDataStore createTable(JDBCDataStore ds, SimpleFeatureSource source) throws FactoryException {
        System.out.println(source.getSchema());

        System.setProperty("org.geotools.referencing.forceXY", "true");
        try {
            SimpleFeatureType simpleFeatureType = modifiedSchema(source.getSchema(), source.getName());
//            ds.createSchema(SimpleFeatureTypeBuilder.retype(simpleFeatureType, CRS.decode("EPSG:4326")));
            ds.createSchema(SimpleFeatureTypeBuilder.retype(simpleFeatureType, DefaultGeographicCRS.WGS84));

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Failed to create the PostgreSQL data table");
        }
        return ds;
    }

    /**
     * @return
     * @Author zhaoxw
     * @Description //TODO  修改表结构，新增geom列和gid主键
     * @Date 15:47 2023/12/29
     **/
    public SimpleFeatureType modifiedSchema(SimpleFeatureType sourceSchema, Name newTableName) throws Exception {
        System.setProperty("org.geotools.referencing.forceXY", "true");
        // 创建新的SimpleFeatureTypeBuilder
        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        builder.setName(newTableName);
        // 复制原始的几何和属性信息到新的SimpleFeatureType,并删除geometry的字段
        for (int i = 0; i < sourceSchema.getAttributeCount(); i++) {
            builder.add(sourceSchema.getDescriptor(i));
        }

        builder.add("geom", Geometry.class);
//        builder.add("geom", MultiPolygon.class);
        // 设置默认几何类型字段
        builder.setDefaultGeometry("geom");
        // 添加新的一列作为主键
        builder.add("gid", Integer.class);
        // 构建并返回修改后的SimpleFeatureType
        return builder.buildFeatureType();
    }

    /**
     * @return
     * @Author zhaoxw
     * @Description //TODO 将shapefile的数据存入数据表中,坐标系做强转，转化为4326的坐标系
     * @Date 15:47 2023/12/29
     **/
    @Override
    public String shp2Table(JDBCDataStore ds, SimpleFeatureSource source) throws FactoryException, IOException, SQLException {

        System.setProperty("org.geotools.referencing.forceXY", "true");

        SimpleFeatureIterator features = null;
        // 坐标转换
        CoordinateReferenceSystem sourceCRS = source.getSchema().getCoordinateReferenceSystem();
//        CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:4326");
        CoordinateReferenceSystem targetCRS = DefaultGeographicCRS.WGS84;
        // 获取源坐标系和目标坐标系
        MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);
        // 表名为shp文件的名字
        String tableName = source.getSchema().getTypeName().toLowerCase();

        try {
            FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(tableName, Transaction.AUTO_COMMIT);
            SimpleFeatureCollection featureCollection = source.getFeatures();
            // 创建图层数据迭代器
            features = featureCollection.features();
            // 进行逐行写入
            Integer gid = 1;
            while (features.hasNext()) {
                try {
                    writer.hasNext();
                    SimpleFeature next = writer.next();
                    SimpleFeature feature = features.next();
                    // 坐标转换,用其他的库了
                    Geometry geometry = (Geometry) feature.getDefaultGeometry();
                    Geometry transformedGeometry = JTS.transform(geometry, transform);
                    next.setDefaultGeometry(transformedGeometry);
//                    System.out.println(feature.getID());
//                    System.out.println(transformedGeometry);
//                    //自己要求的字段也给赋值
//                    next.setAttribute("gid", feature.getID().substring(feature.getID().lastIndexOf(".") + 1, feature.getID().length()));
                    next.setAttribute("gid", gid++);
//                    next.setAttribute("geom", feature.getDefaultGeometry());
                    next.setAttribute("geom", transformedGeometry);

                    int attributeCount = feature.getAttributeCount();
                    for (int i = 0; i < attributeCount; i++) {
                        next.setAttribute(i, feature.getAttribute(i));
                    }
                    writer.write();
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("添加数据的方法错误：" + e.toString());
                    continue;
                }
            }
            writer.close();
            System.out.println("导入成功");

        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("创建写入条件失败：" + e.toString());
            return tableName + "导入失败";
        } finally {
            ds.dispose();
            features.close();
        }

        return tableName;

    }


    @Override
    public boolean insertTableDept(String tablename) {
        String insertSQL = String.format("INSERT INTO t_table_dept(tablename, dept_id,createtime) VALUES ('%s', '%s','%s')", tablename, getDeptId(),LocalDateTime.now().toString());
        importShp2PgRepository.exeSql(insertSQL);
        return true;
    }


    /**
     * @return
     * @Author zhaoxw
     * @Description //TODO  multipartFile转为file
     * @Date 15:48 2023/12/29
     **/
    @Override
    public File convertMultipartFilrToFile(MultipartFile multipartFile) throws IOException {
        File file = File.createTempFile(multipartFile.getOriginalFilename(), ".shp");
        FileCopyUtils.copy(multipartFile.getBytes(), file);
        return file;
    }

    /**
     * @return
     * @Author zxw
     * @Description //TODO  前端传入shpFiles文件，File
     * @Date 20:38 2023/11/4
     * @Param
     **/
    @Override
    public String multipartFileShp2File(MultipartFile[] shpFiles) {

        File fileDir = new File(shpFile);
        if (!fileDir.exists()) {
            //如果文件夹不存在，创建文件夹
            fileDir.mkdirs();
        }
        SimpleDateFormat df_ = new SimpleDateFormat("澄海项目yyyy年MM日dd_HH时mm分ss秒");
        //设置日期格式
        String dirName_ = df_.format(new Date()) + "前端上传shp目录";
        // new Date()为获取当前系统时间
        String targetPath = shpFile + dirName_;

        File targetPathFile = new File(targetPath);
        if (!targetPathFile.exists()) {
            targetPathFile.mkdir();
        }
        try {//shpFiles是前台传入文件.dbf、.prj、.sbn、.sbx、.shp、.shx、.xml
            //保存数据
            for (int i = 0; i < shpFiles.length; i++) {
                shpFiles[i].transferTo(new java.io.File(targetPath + File.separator + shpFiles[i].getOriginalFilename().toLowerCase().trim()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //根据路径读取shp文件  搜索.shp结尾的文件,suffix为后缀的意思
        String suffix = "shp";
        ScanSuffix(targetPath, suffix);
        String pathShp = null;
        for (String fileName : ScanSuffixFiles) {
            pathShp = fileName;
        }
//        targetPathFile.deleteOnExit();
        return pathShp;

    }


    /**
     * @return
     * @Author zhaoxw
     * @Description //TODO
     * @Date 13:20 2024/1/16
     **/
    @Override
    public String delShpByName(String shpName) {
        try {
            List<Map> list = importShp2PgRepository.findTableNameInLayerTable(shpName);
            //表没有在t_layer中
            if (null == list || list.size() == 0) {
                //表名全是数字的话  需要加""。
                if (shpName.matches("\\d+")) {
                    shpName = "\"" + shpName + "\"";
                }
                importShp2PgRepository.delTable(shpName);
                importShp2PgRepository.delTableInTableDept(shpName, getDeptId().toString());

                return "删除成功";
            } else {

                return shpName + "已在表t_layer中绑定";

            }
        } catch (Exception e) {
            return "删除失败";
        }

    }

    public void ScanSuffix(String path, String suffix) {
        File file, tempFile;
        file = new File(path);
        if (!file.isDirectory()) {
            return;
        }
        if (suffix.isEmpty()) {
            return;
        }
        String[] fileList = file.list();
        for (String fileName : fileList) {
            tempFile = new File(path + File.separator + fileName);
            if (tempFile.isDirectory()) {
            }
            if (tempFile.isFile()) {
                String[] splitFileName = fileName.split(File.separator + ".");
                String ext = splitFileName[splitFileName.length - 1];
                if (ext.equals(suffix)) {
                    ScanSuffixCount += 1;
                    ScanSuffixFiles.add(path + File.separator + fileName);
                }
            }
        }
    }

    /**
     * @return
     * @Author zhaoxw
     * @Description // 点或者线shp 转面shp
     * @Date 10:09 2024/2/22
     **/
    @Override
    public void toMultipolygon(String tablename) {
        //先判断tablename是点或者线shp
        List typeList = Arrays.asList("POINT", "MULTIPOINT", "MULTILINESTRING", "LINESTRING");
        String geomType = importShp2PgRepository.findGeomType(tablename);
        //如果是点或者线shp 就转换为面,方法是更新点或者线shp的geom字段为面
        if (typeList.contains(geomType)) {
            List<GeometryPojo> geometryPojoList = importShp2PgRepository.findGeo(tablename);

            for (GeometryPojo geometryPojo : geometryPojoList) {
                importShp2PgRepository.updatGeom(tablename, geometryPojo.getMultipolygon(), geometryPojo.getGid());
            }
        }

    }

    @Override
    public Integer insertVectorByDraw(SubtaskGeom subtaskGeom) {
        String wktStr = subtaskGeom.getGeomStr();
        String geom = "";
        if (wktStr.toUpperCase().contains("POLYGON") && !wktStr.toUpperCase().contains("MULTI")) {
            String wktMultipolygon = wktStr.replace("POLYGON ((", "MULTIPOLYGON (((").replace("))", ")))");
            geom = "ST_SetSRID(ST_GeomFromText('" + wktMultipolygon + "'), 4326)";
        } else {
            geom = "ST_SetSRID(ST_GeomFromText('" + wktStr + "'), 4326)";
        }
        subtaskGeom.setGeomStr(geom);
        subtaskGeom.setCreatetime(LocalDateTime.now());
        importShp2PgRepository.insert(subtaskGeom);
        Integer keyId = subtaskGeom.getId();

        if (wktStr.toUpperCase().contains("POINT") || wktStr.toUpperCase().contains("LINESTRING") ||
                wktStr.toUpperCase().contains("MULTIPOINT") || wktStr.toUpperCase().contains("MULTILINESTRING")) {
            GeometryPojo geometryPojo = importShp2PgRepository.bufferGeom(keyId);
            importShp2PgRepository.toMultiPolygon(geometryPojo.getMultipolygon(), keyId);
        }
        return keyId;
    }


}












